"""
Thanks to html5 boilerplate at http://html5boilerplate.com/   for html+css+js foundation.
Thanks to cherry py         at http://www.cherrypy.org/       for this webserver.
Thanks to mako              at http://www.makotemplates.org/  for the template engine.
Thanks to markup.py         at http://markup.sourceforge.net/ for the html formatting engine.
Thanks to http://www.w3schools.com/ you all know why!

I am trying not to use js in this project: do it all in my favorite Python!

TODO:
2. just before creatig user/course etc. ask user for confirmation.
3. do I still need fancy password with logout?
4. need model classes
5. need view classes
"""

import os
import cherrypy
import markup
from markup import oneliner as Q
from glob import glob
from random import randint
from mako.template import Template

ROOT=os.path.abspath('.')

# list of admin users
ADMIN = [_.strip() for _  in open('%s/admin' % ROOT) if _.strip()]

def render(title, body, **kwd):
    """
    """
    user = cherrypy.session.get('loggedin')
    if user:
        title = '%s - Hi %s' % (title, user)
    else:
        user = ''
    return Template(filename='template.html').render(title='Golf Shorthand', subtitle=title, body=body, user=user, **kwd)

class Gateway(object):
    """
    """
    PWPOSTFIX = str(randint(10,99))
    REALM = 'digits [%s]' % PWPOSTFIX

    @classmethod
    def getpassword(cls, u):
        """
        """
        password = open('db/player/%s' % u).readlines()[-1].split()[1]
        return password

    @classmethod
    def checkpassword(cls, r, u, p):
        """
        This was tricky to write...
        I use password prefix that changes every time server is re-started.
        I also use sessions to record user name and record attempt to log out.
        The main problem was basic_auth has no provision for logout.
        """
        #if u==cherrypy.session.get('loggedin'):
        #    return True
        cherrypy.session['loggedin'] = ''
        #print 'check [%s] [%s] [%s]' % (r,u,p)
        if r!=cls.REALM:
            #print 'nologin realm', r
            return False
        if u in [os.path.basename(_) for _ in glob('db/player/*')]:
            if p != cls.getpassword(u)+cls.PWPOSTFIX:
                #print 'nologon user [%s] password [%s]' % (u,p)
                return False
            if cherrypy.session.get('loggedout'):
                #print 'logged out', u
                cherrypy.session['loggedout'] = False
                return False
            #print 'good login', u
            cherrypy.session['loggedin'] = u
            return True
        #print 'nologin', u
        return False

    def validate_name(self, name):
        """
        """
        return name.isalnum()

    def validate_email(self, email):
        """
        """
        return len(email.split('@'))==2

    def created_html(self):
        """
        """
        page = markup.page(mode='xml')
        page.button('Continue to Main Site', onclick="window.location='/index/registered'")
        return page

    def gateway_html(self):
        """
        """
        page = markup.page(mode='xml')
        page.button('Registered User', onclick="window.location='/index/registered'")
        page.button('New User', onclick="window.location='/index/register'")
        return page

    def registered_html(self):
        """
        """
        page = markup.page(mode='xml')
        page.button('Login', onclick="window.location='/home'")
        page.p('To login, you must add the digits above to the end of your password.')
        page.p('E.g. if your password is golf and you see (digits [23]) then. type golf23 for your password')
        return page

    def register_html(self, name='', email=''):
        """
        """
        page = markup.page(mode='xml')
        page.form(action='/index/create', method='post')
        page.fieldset()
        page.label('Username')
        page.br()
        page.input(name='name', type='text', required='required', value=name)
        page.br()
        page.label('Email')
        page.br()
        page.input(name='email', type='email', required='required', value=email)
        page.br()
        page.label('Password')
        page.br()
        page.input(name='pwd1', type='password', required='required')
        page.br()
        page.label('Verify Password')
        page.br()
        page.input(name='pwd2', type='password', required='required')
        page.br()
        page.br()
        page.input(type='submit', value='Create User')
        page.fieldset.close()
        page.form.close()
        return page

    @cherrypy.expose
    def index(self, *arg, **kwd):
        """
        """
        digits = ' (%s)' % self.REALM
        user = cherrypy.session.get('loggedin')
        print 'index user [%s] arg [%s] kwd [%s] %s' % (user, arg, kwd, digits)
        if arg and arg[0]=='registered':
             return render('Registered User'+digits, self.registered_html())
        if arg and arg[0]=='register':
            return render('', self.register_html())
        if arg and arg[0]=='create':
            return self.create_user(**kwd)
        if arg and arg[0]=='logout':
            cherrypy.session['loggedin'] = ''
            cherrypy.session['loggedout'] = True
            raise cherrypy.HTTPRedirect('/index')
        if user:
             return render('Registered User'+digits, self.registered_html())
        return render('Gateway', self.gateway_html())

    def create_user(self, name, email, pwd1, pwd2):
        """
        """
        title = 'Register'
        name = name.strip()
        email = email.strip()
        fname = name.lower().replace(' ','')
        if not self.validate_name(fname):
            return render (title, self.register_html(name=name, email=email), error='invalid/missing user')
        userdb = 'db/player/%s' % fname
        if os.path.exists(userdb):
            return render (title, self.register_html(name=name, email=email), error='user already exists')
        if not self.validate_email(email):
            return render (title, self.register_html(name=name, email=email), error='invalid/missing email')
        emaildb = 'db/player/%s' % email
        if os.path.exists(emaildb):
            return render (title, self.register_html(name=name, email=email), error='email already exists')
        if not pwd1 or (pwd1!=pwd2):
            return render (title, self.register_html(name=name, email=email), error='missing/bad passwords')
        h=open(userdb,'w')
        print >>h, 'name', name
        print >>h, 'pwd', pwd1
        h.close()
        os.system ('ln -s %s/%s %s/%s' % (ROOT, userdb, ROOT, emaildb))
        return render('Success', self.created_html(), info='Created new user [%s] email [%s]' % (name, email))

    def list_html(self):
        """
        """
        P = markup.page(mode='xml')
        P.button('Done', onclick="window.location='/home'")
        P.hr()
        P.table()
        P.tr(Q.th(('User Name', 'Name')))
        for p in sorted(glob('db/player/*')):
            tds = [os.path.basename(p)]
            for l in open(p).readlines()[:-1]: # miss out password must always be last
                tds.append(' '.join(l.strip().split()[1:]))
            P.tr(Q.td(tds))
        P.table.close()
        return P

    @cherrypy.expose
    def _list(self):
        """
        Hidden url for admin.
        """
        print cherrypy.session.get('loggedin'), ADMIN
        if cherrypy.session.get('loggedin') not in ADMIN:
            return render('Gateway', self.gateway_html())
        return render('Users', body=self.list_html())

    @cherrypy.expose
    def default(self, *arg, **kwd):
        """
        """
        if cherrypy.session.get('loggedin'):
            raise cherrypy.HTTPRedirect('/home')
        raise cherrypy.HTTPRedirect('/index')

class Home(object):
    """
    """

    def login_html(self):
        """
        """
        P = markup.page(mode='xml')
        if cherrypy.session.get('loggedin') in ADMIN:
            P.button('Users', onclick="window.location='/_list'")
        P.button('View/Create Courses', onclick="window.location='/course'")
        P.button('View/Create Rounds', onclick="window.location='/round'")
        P.button('Logout', onclick="window.location='/index/logout'")
        return P

    @cherrypy.expose
    def index(self):
        """
        """
        return render('Select', self.login_html())

class CourseModel(object):
    """
    """
    DB = '%s/db/course' % ROOT

    def __init__(self):
        """
        """
        assert os.path.exists(self.DB)
        self.cache_name = None
        self.cache = None

    def list(self):
        """
        """
        return sorted([os.path.basename(_) for _ in glob('%s/*' % self.DB)])

    def fillcache(self, cname):
        """
        """
        if cname and self.cache_name==cname:
            return
        self.cache_name = cname
        n,h,t = cname.split('-')
        self.cache_holes = int(h)
        self.cache_tee = t
        self.cache = dict()
        fname = '%s/%s' % (self.DB, cname)
        if not os.path.exists(fname):
            raise cherypy.HTTPRedirect('/course')
        for l in open(fname):
            bits = l.strip().split()
            k,v =bits[0],' '.join(bits[1:])
            self.cache[k] = v

    def name(self, cname):
        """
        """
        self.fillcache(cname)
        return self.cache['name']

    def holes(self, cname):
        """
        """
        self.fillcache(cname)
        return self.cache_holes

    def tee(self, cname):
        """
        """
        self.fillcache(cname)
        return self.cache_tee

    def hole(self, cname, hole):
        """
        """
        self.fillcache(cname)
        hstr = '%02d' % hole
        par = self.cache['h%spar' % hstr]
        si  = self.cache['h%ssi'  % hstr]
        yds = self.cache['h%syds' % hstr]
        return int(par), int(si), int(yds)

class Course(object):
    """
    """
    model = CourseModel()

    def validate_hcap(self, hcap):
        """
        """
        return hcap.isdigit() and 0<int(hcap)<40

    def validate_tee(self, tee):
        """
        """
        return tee in ('red', 'yellow', 'white')

    def validate_holes(self, holes):
        """
        """
        return holes.isdigit() and 9<=int(holes)<=18

    def validate_name(self, name):
        """
        """
        return name.replace('-','').isalnum()

    def index_html(self):
        """
        """
        P = markup.page(mode='xml')
        P.button('Home', onclick="window.location='/home'")
        P.button('List Courses', onclick="window.location='/course/list'")
        P.button('Add New Course', onclick="window.location='/course/create'")
        return P

    @cherrypy.expose
    def index(self):
        """
        """
        return render('Course Index', self.index_html())

    def create_html(self, **kwd):
        """
        """
        P = markup.page()
        P.button('Cancel', onclick="window.location='/course'")
        P.hr()
        P.form(action='/course/create', method='post')
        P.fieldset()
        if 'CONFIRMED' in kwd:
            P.input(type='submit', value='Confirm Details', name='CONFIRMED')
            P.br()
            P.label('')
            P.br()
        P.label('Course Name')
        P.br()
        P.input(name='name', type='text', required='required', value=kwd.get('name'))
        P.br()
        P.label('Tee')
        P.br()
        tee=kwd.get('tee')
        P.select(name='tee')
        for t in ('yellow', 'red', 'white'):
            if tee==t:
                P.option(t.capitalize(), value=t, selected='selected')
            else:
                P.option(t.capitalize(), value=t)
        P.select.close()
        P.br()
        P.label('Holes')
        P.br()
        holes = kwd.get('holes', '18')
        P.input(name='holes', type='number', min='9', max='18', required='required', value=holes)
        P.br()
        for h in range(1,19):
            if h in (1,10):
                P.label('Par/Si/Yds')
                P.br()
            hstr = '%02d' % h
            hpar = 'h%spar' % hstr
            hsi  = 'h%ssi'  % hstr
            hyds = 'h%syds' % hstr
            P.label(hstr)
            P.select(name=hpar, class_='narrow')
            for p in ('3', '4', '5'):
                if p==kwd.get(hpar):
                    P.option('Par %s' % p, value=p, selected='selected')
                else:
                    P.option('Par %s' % p, value=p)
            P.select.close()
            P.select(name=hsi, class_='narrow')
            for si in range(int(holes)):
                si = str(si+1)
                if si==kwd.get(hsi):
                    P.option('Si %s' % si, value=si, selected='selected')
                else:
                    P.option('Si %s' % si, value=si)
            P.select.close()
            P.input(type='number', max='650', required='required', value=kwd.get(hyds, '200'), name=hyds, class_='narrow')
            P.br()
        P.label()
        P.br()
        P.input(type='submit', value='Check Course')
        P.br()
        P.fieldset.close()
        P.form.close()
        return P

    @cherrypy.expose
    def create(self, *arg, **kwd):
        """
        """
        title = 'Create Course'
        if not kwd:
            return render(title, self.create_html())

        name  = kwd.get('name',  '').strip()
        tee   = kwd.get('tee',   '').strip().lower()
        holes = kwd.get('holes', '').strip()

        # simple parameter validation
        fname = '%s-%s-%s' % (name.lower().replace(' ',''), holes, tee)
        if not self.validate_name(fname):
            return render (title, self.create_html(**kwd), error='invalid/missing name [%s]' % name)
        db = 'db/course/%s' % fname
        if os.path.exists(db):
            return render (title, self.create_html(**kwd), error='course [%s] already exists' % name)
        if not self.validate_tee(tee):
            return render (title, self.create_html(**kwd), error='invalid/missing tee [%s]' % tee)
        if not self.validate_holes(holes):
            return render (title, self.create_html(**kwd), error='invalid/missing holes [%s]' % holes)

        # check that details look ok
        siset = set()
        ydscount = 0
        parcount = 0
        pardict = {'3':0, '4':0, '5':0}
        for h in range(int(holes)):
            lookfor = 'h%02d' % (h+1)
            found = [_ for _ in kwd if (_.startswith(lookfor) and kwd[_])]
            if len(found)!=3:
                return render (title, self.create_html(**kwd), error='course [%s] hole [%s] missing' % (name, lookfor))
            siset.add('%02d' % int(kwd['%ssi' % lookfor]))
            ydscount += int(kwd['%syds' % lookfor])
            parcount += int(kwd['%spar' % lookfor])
            pardict[kwd['%spar' % lookfor]] += 1
        if len(siset)!=18:
            return render (title, self.create_html(**kwd), error='course [%s] si incorrect expected 18 found [%s]' % (name, ','.join(sorted(siset))))

        # if you get here then all looks good get user to confirm
        if not 'CONFIRMED' in kwd:
            kwd['CONFIRMED']=True
            return render (title, self.create_html(**kwd),
                info=('Confirm %s %s %s %s*Par3 %s*Par4 %s*Par5 Par %s %sYds' % (name, holes, tee, pardict['3'], pardict['4'], pardict['5'], parcount, ydscount)))

        # user must have confirmed!
        h=open(db,'w')
        print >>h, 'name', name
        for hole in range(int(holes)):
            lookfor = 'h%02d' % (hole+1)
            for key in  sorted([_ for _ in kwd if _.startswith(lookfor)]):
                print >>h, key, kwd[key]
        h.close()
        raise cherrypy.HTTPRedirect('/course')

    def list_html(self):
        """
        """
        P = markup.page()
        P.button('Done', onclick="window.location='/course'")
        P.hr()
        P.table()
        P.tr(Q.th(['Course-Holes-Tee', 'Name', 'Par', 'Yds', 'View']))
        for course in sorted(glob('db/course/*')):
            par = yds = 0
            for l in open(course):
                bits = l.strip().split()
                key, rest = bits[0], bits[1:]
                if 'par' in key:
                    par += int(rest[0])
                elif 'yds' in key:
                    yds += int(rest[0])
                elif 'name' in key:
                    name = ' '.join(rest)
            cname = os.path.basename(course)
            P.tr(Q.td([cname, name, par, yds, Q.a('view', href='/course/list/%s' % cname)]))
        P.table.close()
        return P

    def view_html(self, course):
        """
        """
        fname = 'db/course/%s' % course
        if not os.path.exists(fname):
            raise cherypy.HTTPRedirect('/course')
        kwd = {}
        for l in open(fname):
            bits = l.strip().split()
            k,v =bits[0],' '.join(bits[1:])
            kwd[k] = v
        P = markup.page()
        P.button('Done', onclick="window.location='/course/list'")
        P.hr()
        P.label(kwd['name'])
        P.table()
        P.tr(Q.th(['Hole', 'Par', 'Si', 'Yds']))
        yds = 0
        for h in range(18):
            if h==9:
                P.tr(Q.td(['', '', '', yds]))
            hstr = '%02d' % (h+1)
            ydsstr = kwd['h%syds'%hstr]
            yds += int(ydsstr)
            P.tr(Q.td([hstr, kwd['h%spar'%hstr], kwd['h%ssi'%hstr], ydsstr]))
        P.tr(Q.td(['', '', '', yds]))
        P.table.close()
        return P

    @cherrypy.expose
    def list(self, *arg):
        """
        """
        if not arg:
            return render('Courses', self.list_html())
        arg = ''.join(arg)
        return render(arg, self.view_html(arg))

class RoundModel(object):
    """
    """
    DB = '%s/db/round' % ROOT

    def __init__(self):
        """
        """
        assert os.path.exists(self.DB)

    def list(self, user):
        """
        """
        return sorted([_ for _ in glob('%s/%s/*' % (self.DB, user))])

    def shortcount(self, short):
        """
        """
        count = 0
        short = short.replace('M','')
        if short[-1].isdigit():
            count += int(short[-1])
            short = short[:-1]
        count += len(short)
        return count

    def list_detail(self, user):
        """
        """
        for f in self.list(user):
            dt = os.path.basename(f)
            score = 0
            for l in open(f):
                bits = l.strip().split()
                if bits[0]=='course':
                    course = bits[1]
                elif bits[0].isdigit():
                    score += self.shortcount(bits[1])
            yield dt, course, score

    def get_dir(self, user):
        """
        """
        return '%s/%s' % (self.DB, user)

    def get_file(self, user, **kwd):
        """
        """
        return '%s/%s-%s' % (self.get_dir(user), kwd['date'], kwd['time'].replace(':',''))

    def validate(self, user, **kwd):
        """
        """
        if not user:
            return 'invalid/missing user'
        udir = self.get_dir (user)
        if not os.path.exists(udir):
            print 'created', udir
            os.mkdir(udir)
        course = kwd.get('course')
        if not course:
            return 'invalid/missing course'
        date = kwd.get('date')
        if not date or len(date)!=10 or len(date):
            return 'invalid/missing date'
        time = kwd.get('time')
        if not time or len(time)!=5 or len(time.split(':'))!=2:
            return 'invalid/missing time'
        note = kwd.get('note')
        if not note:
            return 'invalid/missing note'
        ufile = self.get_file(user, **kwd)
        if os.path.exists(ufile):
            return 'round [%s] already exists' % ufile
        weather = kwd.get('weather')
        if not weather:
            return 'invalid/missing weather'
        for hole in range(Course.model.holes(course)):
            hole += 1
            hp=kwd.get('hp%02d' % hole)
            if not hp:
                return 'hole [%s] invalid/missing hole (par)' % hole
            score = int(kwd.get(('score%02d' % hole), '0'))
            short = kwd.get('short%02d' % hole).upper().replace('M','')
            if short[-1].isdigit():
                puts = int(short[-1])
                short = short[:-1]
                if short[-1]!='G':
                    return 'hole [%s] invalid/missing shorthand (missing green)' % hole
            elif short[-1]=='H':
                puts = 0
            else:
                return 'hole [%s] invalid/missing shorthand (missing puts)' % hole
            if not short.isalpha():
                return 'hole [%s] invalid/missing shorthand (alphabetic)' % hole
            for c in short:
                if c not in ('F', 'S', 'L', 'R', 'G', 'H', 'O', 'B', 'P', 'X', 'M'):
                    return 'hole [%s] invalid/missing shorthand (bad characters)' % hole
            if len(short)+puts != score:
                return 'hole [%s] score [%s] does not match shorthand [%s]' % (hole, score, len(short)+puts)
        return ''

    def score(self, **kwd):
        """
        """
        result= 0
        for hole in range(Course.model.holes(kwd['course'])):
            result += int(kwd['score%02d' % (hole+1)])
        return result

    def write(self, user, **kwd):
        """
        """
        h=open(self.get_file(user, **kwd), 'w')
        print >>h, 'course', kwd['course']
        print >>h, 'weather', kwd['weather']
        print >>h, 'note', kwd['note']
        for hole in range(Course.model.holes(kwd['course'])):
            print >>h, hole+1, kwd['short%02d' % (hole+1)]
        h.close()

    def get_file2(self, user, dt):
        """
        """
        return '%s/%s' % (self.get_dir(user), dt)

    def read(self, user, dt):
        """
        """
        shorthand = []
        for l in open(self.get_file2(user,dt)):
            bits = l.strip().split()
            key = bits[0]
            value = ' '.join(bits[1:])
            if key=='course':
                course = value
            elif key=='weather':
                weather = value
            elif key=='note':
                note = value
            elif key.isdigit():
                shorthand.append(value)
        return course, weather, note, shorthand

class RoundView(object):
    """
    """

    def index(self, user):
        """
        """
        H = markup.page()
        H.button('Home', onclick="window.location='/home'")
        H.button('List %s Rounds' % user, onclick="window.location='/round/list/%s'" % user)
        H.button('Add New %s Round' % user, onclick="window.location='/round/create/%s'" % user)
        return H

    def list(self, user):
        """
        """
        H = markup.page()
        H.button('Home', onclick="window.location='/home'")
        H.button('Rounds', onclick="window.location='/round/'")
        H.hr()
        H.table()
        H.tr(Q.th(['Date-Time', 'Course', 'Score', 'View']))
        for dt, c, s in Round.model.list_detail(user):
            H.tr(Q.td([dt, c, s, Q.a('view', href='/round/list/%s/%s' % (user, dt))]))
        H.table.close()
        return H

    def show(self, user, dt):
        """
        """
        H = markup.page(mode='xml')
        H.button('Done', onclick="window.location='/round/list/%s'" % user)
        H.hr()
        cmodel = Course.model
        course, weather, note, shorthand = Round.model.read(user, dt)
        H.golf(course=cmodel.name(course), player=user, date=dt)
        assert cmodel.holes(course) == len(shorthand)
        for hole, short in enumerate(shorthand):
            par, si, yds = cmodel.hole(course, hole+1)
            if par==3:
                H.par3(short, si=si, yds=yds)
            elif par==4:
                H.par4(short, si=si, yds=yds)
            else:
                H.par5(short, si=si, yds=yds)
        H.golf.close()
        return H

    def create(self, user, **kwd):
        """
        """
        H = markup.page()
        H.button('Cancel', onclick="window.location='/round'")
        H.hr()
        H.form(action='/round/create/%s' % user, method='post')
        H.fieldset()
        if 'CONFIRMED' in kwd:
            H.input(type='submit', value='Confirm Details', name='CONFIRMED')
            H.br()
            H.label('')
            H.br()
        H.label('Course Name')
        H.br()
        course = kwd.get('course')
        H.select(name='course')
        cmodel = Course.model
        for c in cmodel.list():
            if course==c:
                H.option(c, value=c, selected='selected')
            else:
                H.option(c, value=c)
        H.select.close()
        H.label('Date')
        H.input(name='date', type='date', required='required', value=kwd.get('date'))
        H.br()
        H.label('Time')
        H.input(name='time', type='time', required='required', value=kwd.get('time', '12:00'))
        H.br()
        H.label('Note')
        H.input(name='note', type='text', required='required', value=kwd.get('note'), placeholder='Notes')
        H.br()
        H.label('Weather')
        H.br()
        weather = kwd.get('weather')
        H.select(name='weather')
        for w in ('sunny', 'showers', 'freezing', 'heavy rain', 'light rain', 'foggy', 'overcast', 'windy', 'very windy', 'warm', 'cold', 'hot', 'storm', 'snow'):
            if weather==w:
                H.option(w.capitalize(), value=w, selected='selected')
            else:
                H.option(w.capitalize(), value=w)
        H.select.close()
        if course:
            H.label(cmodel.name(course))
            H.br()
            H.label('Tee: %s' % cmodel.tee(course))
            H.label('Holes: %s' % cmodel.holes(course))
            H.br()
            H.label('Hole (Par) -- Score -- Shorthand')
            H.br()
            for h in range(0,cmodel.holes(course)):
                h+=1
                par, si, yds = cmodel.hole(course, h)
                if h in (1,10):
                    H.label('---')
                    H.br()
                scorekwd = 'score%02d' % h
                shortkwd = 'short%02d' % h
                hpkwd = 'hp%02d' % h
                H.input(value='%02d (par%d)' % (h, par), type='text', readonly='readonly', class_='narrow', name=hpkwd)
                H.input(type='text', required='required', name=shortkwd, class_='narrow', value=kwd.get(shortkwd, '').upper(), placeholder='Shorthand')
                H.input(type='number', required='required', class_='very_narrow', min='1', max='12', name=scorekwd, value=kwd.get(scorekwd, par))
                H.br()
        H.label('Done')
        H.br()
        H.input(type='submit', value='Check Round')
        H.br()
        H.fieldset.close()
        H.form.close()
        return H

class Round(object):
    """
    """
    model = RoundModel()
    view  = RoundView()

    def get_user(self):
        """
        """
        user = cherrypy.session['loggedin']
        if not user:
            self.user = None
            raise HTTPRedirect('/gateway')
        self.user = user

    @cherrypy.expose
    def index(self):
        """
        """
        self.get_user()
        return render('Rounds', self.view.index(self.user))

    @cherrypy.expose
    def create(self, user, **kwd):
        """
        """
        title = 'Create Round'
        if not kwd:
            return render(title, self.view.create(user))

        # validate parameters
        error = self.model.validate(user, **kwd)
        if error:
            return render (title, self.view.create(user, **kwd), error=error)

        # if you get here then all looks good get user to confirm
        if not 'CONFIRMED' in kwd:
            kwd['CONFIRMED']=True
            return render (title, self.view.create(user, **kwd), info='Confirm score %s %s' % (user, self.model.score(**kwd)))

        self.model.write(user, **kwd)

        #return render (title, self.view.create(user, **kwd), info='Done %s %s' % (user, self.model.score(**kwd)))
        raise cherrypy.HTTPRedirect('/round')

    @cherrypy.expose
    def list(self, user, round=None):
        """
        """
        if round:
            return render(round, self.view.show(user,round), golf=True)
        return render('List Rounds', self.view.list(user))

class Match(object):
    """
    """

    @cherrypy.expose
    def index(self):
        """
        """
        return render('match-index', '')

    @cherrypy.expose
    def create(self):
        """
        """
        return render('match-create', '')

# Website Structure

root = Gateway()
root.home = Home()
root.course = Course()
root.round = Round()
root.match = Match()

# Cherry Py config

_check_user = {'tools.auth_basic.on': True,
                'tools.auth_basic.realm': Gateway.REALM,
                'tools.auth_basic.checkpassword': Gateway.checkpassword}

_root_config = {'tools.staticdir.root': ROOT,
                'tools.sessions.on': True}

def _staticdir(where):
    """
    """
    return {'tools.staticdir.on':True,
            'tools.staticdir.dir': where}

config = {'/'   : _root_config,
          '/js' : _staticdir('js'),
          '/css': _staticdir('css'),
          '/home' : _check_user,
          '/round' : _check_user,
          '/match' : _check_user,
          '/course' : _check_user}

cherrypy.server.socket_host = '0.0.0.0'
cherrypy.server.socket_port = 8080

cherrypy.quickstart(root, config=config)
